//*****************************************************************************
//
// startup_gcc.c - Boot code for gnu tools for Stellaris.
//
// Copyright (c) 2006-2007 Luminary Micro, Inc.  All rights reserved.
//
// Software License Agreement
//
// Luminary Micro, Inc. (LMI) is supplying this software for use solely and
// exclusively on LMI's microcontroller products.
//
// The software is owned by LMI and/or its suppliers, and is protected under
// applicable copyright laws.  All rights are reserved.  Any use in violation
// of the foregoing restrictions may subject the user to criminal sanctions
// under applicable laws, as well as to civil liability for the breach of the
// terms and conditions of this license.
//
// THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
// OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
// LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 323 of the Stellaris boot loader.
//
//*****************************************************************************

#include "../../hw_memmap.h"
#include "boot_loader.h"

//*****************************************************************************
//
// The following are constructs created by the linker, indicating where the
// the "data" and "bss" segments reside in memory.  The initializers for the
// for the "data" segment resides immediately following the "text" segment.
//
//*****************************************************************************
extern unsigned long _edata;
extern unsigned long _bss;
extern unsigned long _ebss;

//*****************************************************************************
//
// Forward declaration of the default fault handlers.
//
//*****************************************************************************
void ResetISR(void);
static void IntDefaultHandler(void);
void GPIOIntHandler(void);

//*****************************************************************************
//
// The entry point for the application.
//
//*****************************************************************************
extern void main(void);

//*****************************************************************************
//
//! The minimal vector table for a Cortex M3.  Note that the proper constructs
//! must be placed on this to ensure that it ends up at physical address
//! 0x00000000.  If the auto-baud feature is used then the vector table must
//! grow to encompass the GPIO interrupt A which is used by the auto-baud
//! algorithm.
//
//*****************************************************************************
__attribute__ ((section(".isr_vector")))
void (* const g_pfnVectors[])(void) =
{
    (void (*)(void))((unsigned long)pulStack + sizeof(pulStack)),
                                            // The initial stack pointer
    (void (*)(void))((unsigned long)ResetISR - SRAM_BASE),
                                            // The reset handler
    IntDefaultHandler,                      // The NMI handler
    IntDefaultHandler,                      // The hard fault handler
    IntDefaultHandler,                      // The MPU fault handler
    IntDefaultHandler,                      // The bus fault handler
    IntDefaultHandler,                      // The usage fault handler
#if defined(AUTOBAUD)
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // SVCall handler
    IntDefaultHandler,                      // Debug monitor handler
    0,                                      // Reserved
    IntDefaultHandler,                      // The PendSV handler
    IntDefaultHandler,                      // The SysTick handler
    GPIOIntHandler,                         // GPIO Port A
#endif
};

//*****************************************************************************
//
//! This function handles setting up the boot loader for operation from SRAM.
//!
//! This is the code that gets called when the processor first starts execution
//! following a reset event.  This function copies all of the code from flash
//! to SRAM so that the boot loader itself can be updated in the flash.  This
//! function also takes care of zeroing out the bss section befor calling the
//! main() function which will be run from SRAM.
//!
//! \return This function returns to main().
//
//*****************************************************************************
void
ResetISR(void)
{
    unsigned long *pulSrc, *pulDest;

    //
    // Copy the code and constant data segment initializers from flash to SRAM.
    //
    pulSrc = 0;
    pulDest = (unsigned long *)SRAM_BASE;
    while(pulDest < &_edata)
    {
        *pulDest++ = *pulSrc++;
    }

    //
    // Zero fill the bss segment.
    //
    for(pulDest = &_bss; pulDest < &_ebss; )
    {
        *pulDest++ = 0;
    }

    //
    // Call the application's entry point.  This address is too far for a
    // direct branch.
    //
    __asm
    (
        "ldr    r0,=main\n"
        "bx     r0\n"
    );
}

//*****************************************************************************
//
//! The default handler for any unhandled interrupt.
//!
//! This is the code that gets called when the processor receives an unexpected
//! interrupt.  This simply enters an infinite loop, preserving the system
//! state for examination by a debugger.
//!
//! \return This function never returns.
//
//*****************************************************************************
static void
IntDefaultHandler(void)
{
    //
    // Go into an infinite loop.
    //
    while(1)
    {
    }
}

//*****************************************************************************
//
//! Calls the application at ulBaseAddress.
//!
//! \param ulBaseAddress is the base address in flash of the application to
//!     run.  This should point to a valid interrupt vector table.
//!
//! This function reads the stack pointer from the base address passed in and
//! also moves the vector table to point to the vector table provided by the
//! application.  Once the vector table and stack are configured this function
//! reads out the start address for the application and branches to it.
//!
//! \return This function never returns.
//
//*****************************************************************************
void
CallApplication(unsigned long ulBaseAddress)
{
    __asm(
    "mov r1, #0xE0000000\n"
    "add r1, r1, #0x0000ED00\n"
    "str r0, [r1,#8]\n"
    "ldr sp, [r0], #4\n"
    "ldr r0, [r0]\n"
    "bx  r0\n");
}
